﻿// 601 最小生成树1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <algorithm>
#include <memory.h>


using namespace std;
/*
http://oj.daimayuan.top/course/14/problem/690


给你一张 n个顶点 m条边的无向简单连通图，顶点编号从 1 到 n
，每条边都有一个边权，边权为非负整数。

请求出这张图的最小生成树，只需要输出最小生成树的边权和即可。

输入格式
第一行两个整数 n,m，表示图的顶点数、边数。

接下来 m行，每行三个整数 x,y,z
，表示 x号点与 y号点之间有一条边权为 z的边。

数据保证图中顶点两两连通。

输出格式
输出一行一个数，表示最小生成树的边权和。

样例输入
4 4
1 2 1
2 3 3
3 4 1
1 4 2
样例输出
4
数据规模 
对于所有数据，保证 2≤n≤1000,n−1≤m≤100000,1≤x,y≤n,1≤z≤10000。
*/

const int INF = 0x3f3f3f3f;
int n, m;
const int N = 1010, M = 200010;
int p[N];

struct Edge {
	int a, b, w;
	bool operator < (const Edge& W)const {
		return w < W.w;
	}
}edges[M];;

int find(int x) {
	if (p[x] != x) p[x] = find(p[x]);

	return p[x];
}

int kruskal() {
	sort(edges, edges + m);

	for (int i = 1; i <= n; i++) { p[i] = i; }

	int res = 0; int cnt = 0;
	for (int i = 0; i < m; i++) {
		int a = edges[i].a; int b = edges[i].b; int w = edges[i].w;

		a = find(a); b = find(b);
		if (a != b) {
			p[a] = b;
			res += w;
			cnt++;
		}
	}

	if (cnt < n - 1) return INF;
	return res;
}



int main()
{
	cin >> n >> m;
	for (int i = 0; i < m; i++) {
		int a, b, c;
		cin >> a >> b >> c;
		edges[i].a = a; edges[i].b = b; edges[i].w = c;
	}

	cout << kruskal() << endl;

	return 0;
}

 